import {designPage} from "@peryl/react-compose";
import {$ai, $configuration, $file, AiChatBox, Alert, Button, iChatBoxHistory, PageCard, PageCardContent, PageCardTitle, Plc, Table} from "plain-design";
import {uuid} from "@peryl/utils/uuid";
import {EchartsViewer} from "./EchartsViewer";

export default designPage(() => {

  const http = $configuration.get('http');

  /*const execSql = async () => {
    const data = await http.post<{ result: any }>('/bmw897654321', { content: 'select * from llm_product' });
    console.log(data);
  };*/

  const ddl = `
    用户表llm_user：
    create or replace table plain.llm_user
    (
        id           varchar(50) default uuid()              not null comment '编号' primary key,
        created_at   datetime    default current_timestamp() null comment '创建时间',
        created_by   varchar(50)                             null comment '创建人id',
        updated_at   datetime    default current_timestamp() null comment '最后更新时间',
        updated_by   varchar(50)                             null comment '最后更新人id',

        full_name    varchar(200)                            null comment '用户名称',
        username     varchar(100)                            null comment '用户名',
        password     varchar(40)                             null comment '用户密码',
        member_start datetime                                null comment '开通会员时间',
        member_end   datetime                                null comment '会员截止到期时间',
        constraint llm_user_id_uindex
            unique (id)
    );

    商品表llm_product：
    create or replace table plain.llm_product
    (
        id          varchar(50) default uuid()              not null comment '编号' primary key,
        created_at  datetime    default current_timestamp() null comment '创建时间',
        created_by  varchar(50)                             null comment '创建人id',
        updated_at  datetime    default current_timestamp() null comment '最后更新时间',
        updated_by  varchar(50)                             null comment '最后更新人id',

        name        varchar(200)                            null comment '商品名称',
        price       decimal                                 null comment '商品价格',
        valid_start datetime                                null comment '商品有效开始时间',
        valid_end   datetime                                null comment '商品有效结束时间',
        constraint llm_product_id_uindex
            unique (id)
    );

    订单表llm_order：
    create or replace table plain.llm_order
    (
        id         varchar(50) default uuid()              not null comment '编号' primary key,
        created_at datetime    default current_timestamp() null comment '创建时间',
        created_by varchar(50)                             null comment '创建人id',
        updated_at datetime    default current_timestamp() null comment '最后更新时间',
        updated_by varchar(50)                             null comment '最后更新人id',

        user_id    varchar(200)                            null comment '用户的id，跟llm_user表中的id对应',
        prod_id    varchar(200)                            null comment '商品的id，跟llm_product表中的id对应',
        constraint llm_order_id_uindex
            unique (id)
    );
  `;

  const systemContent = `
    我给你提供几个表的ddl语句，分别是：
    ${ddl}

    现在需要你帮我将用户的描述转化为SQL查询语句，不需要给我返回代码解释；你返回的数据格式是固定的，为JSON数据，结构如下所示：{sql,message,type,charts}
    如果能够升成sql语句，则把sql语句放在结果的sql属性上；如果不能则给出原因放在结果的message属性上；
    最后是用户要求展示的方式，如果展示为列表，则返回结果的type值为list；
    如果展示为图表，返回结果的type值为charts，并且把图表的要求描述放在结果的charts上；
    其他方式的展示方式type值为simple；
  `;

  const handleMessage = async ({ message, userContent, addHistory }: { message: string, userContent: string, addHistory: (history: iChatBoxHistory) => void }): Promise<iChatBoxHistory | iChatBoxHistory[] | void> => {
    try {
      const chatResult1: { sql: string, message: string, type: 'list' | 'charts' | 'simple', charts?: string } = JSON.parse(message);
      console.log('解析用户问题', chatResult1);
      if (!!chatResult1.message) {
        return [{ id: uuid(), role: 'assistant', content: chatResult1.message }];
      }
      if (!chatResult1.sql) {
        return [{ id: uuid(), role: 'assistant', content: '没有生成sql语句，不做处理' }];
      }
      const sqlResult = await http.post<{ result: any }>('/bmw897654321', { content: chatResult1.sql });
      addHistory({ id: uuid(), role: 'assistant', content: chatResult1.sql });

      if (!sqlResult.result.length) {
        return [{ id: uuid(), role: 'assistant', content: '查询不到任何数据' }];
      }

      if (chatResult1.type === 'simple') {
        const chatResult2 = await $ai.chat(`
              用户的提问是"${userContent}"，
              我已经把数据查出来了，数据为:${JSON.stringify(sqlResult.result)}；
              已知的表结构为${ddl}，
              需要你根据表结构以及数据提炼出来答案告诉用户；回答要简洁明确，不需要做解释，也不需要告诉我sql语句；
              `);
        console.log('对用户提问以简单问答的形式展示');
        return [{ id: uuid(), role: 'assistant', content: chatResult2.message }];
      } else if (chatResult1.type === 'list') {
        console.log('对用户提问以列表的形式展示');
        return [{
          id: uuid(), role: 'assistant', render: () => {
            const fields = Object.keys(sqlResult.result[0]);
            return <>
              <Button
                size="mini" label="导出" icon="pi-export"
                onClick={() => $file.export2file({ exportData: sqlResult.result, columns: fields.map(field => ({ header: field, key: field })) })}/>
              <Table data={sqlResult.result} size="mini">
                {fields.map(key => (<Plc title={key} field={key} key={key}/>))}
              </Table>
            </>;
          }
        }];
      } else if (chatResult1.type === 'charts') {
        console.log('对用户提问以图表的形式展示', { sqlResult: sqlResult.result, chatQuestions: chatResult1.charts });

        const chatResult2 = await $ai.chat(`
              用户的提问是"${userContent}"，
              我已经把数据查出来了，数据为:${JSON.stringify(sqlResult.result)}；
              已知的表结构为${ddl}，
              需要你根据表结构以及数据，按照echarts的api规则，生成echarts option的json字符串；
              你只能返回固定的json数据，json数据结构为 {echartsOption,message}，不需要其他的解释说明；
              如果能够生成，则将echarts option的json配置放在结果的echartsOption属性中；
              如果不能生成，将原因放在结果的message属性中；
              `);
        console.log('chatResult2.message', chatResult2.message);
        const chartData2: { echartsOption: any, message?: string } = JSON.parse(chatResult2.message);
        console.log('typeof chartData2.echartsOption', typeof chartData2.echartsOption);
        if (typeof chartData2.echartsOption === "string") {
          try {
            chartData2.echartsOption = JSON.parse(chartData2.echartsOption);
          } catch (e) {
            return [{ id: uuid(), role: 'assistant', content: `JSON数据有误：${chartData2.echartsOption}` }];
          }
        }
        if (!!chartData2.message) {
          return [{ id: uuid(), role: 'assistant', content: chartData2.message }];
        } else {
          return [{
            id: uuid(), role: 'assistant', render: () => (
              <EchartsViewer option={chartData2.echartsOption}/>
            )
          }];
        }
      }
    } catch (e: any) {
      console.error(e);
      return [{ id: uuid(), role: 'assistant', content: JSON.stringify(e.message || e) }];
    }
  };

  return () => (
    <PageCard>
      <PageCardTitle title="自由查询"/>
      <PageCardContent>
        {/*<Button label="执行sql" onClick={execSql}/>*/}
        <AiChatBox
          systemContent={systemContent}
          handleMessage={handleMessage}
          v-slots={{
            prepend: () => (
              <Alert icon={null}>
                <div>1. 在这里你可以自由查询数据库中的表数据，目前仅支持订单表、用户表以及商品表</div>
                <div>2. 比如示例：1)查看商品表所有数据；2)赵六一共花了多少钱；3)李四总共买了多少件商品；4)哪些人买过手表</div>
                <div>3. 可以要求用图表形式展示数据，比如：查看商品数据，以柱状图的形式展示商品价格；</div>
                <div>4. 也可以要求查询表的时候要关联哪些表，比如：查看订单数据，关联用户表以及商品表展示所有字段</div>
                <div>5. 其他示例：查看商品数据，按照商品价格从小到大，以折线图的形式展示商品价格；折线图的x轴展示商品名称；</div>
                <div>6. 其他示例：查询商品数据，关联订单表查询出来商品的销量，最后以饼图的形式展示商品销量</div>
              </Alert>
            )
          }}
        />
      </PageCardContent>
    </PageCard>
  );
});
